/********************************************************************
 * BenchIT - Performance Measurement for Scientific Applications
 * Contact: developer@benchit.org
 *
 * $Id$
 * $URL$
 * For license details see COPYING in the package base directory
 *******************************************************************/
/* included for compatibility, as this kernel uses an older interface of the
 * hardware detection. The functionality is currently migrated to the benchit
 * Tools section (/tools/hw_detect) with extended detection using sysfs as a
 * second source of information.
 ***************************************************************************/
/* TODO: migrate to new hw-detection API*/
#include "arch.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <sys/time.h>
#include <fcntl.h>

#define MAX_OUTPUT 1024
#define DEBUG 0

char output[MAX_OUTPUT];
char *argv[3];

unsigned long long a,b,c,d;
unsigned long long reg_a,reg_b,reg_c,reg_d;

int sh(char* script,int argc, char** args, char* output, int buffersize)
{
 int fd[2],status,i;
 pid_t pid;
 char *directory;
 char *path;
 char *root;
 char **sysfs_argv;
 char *tmp;
 int script_fd;
 int res;
// root=getenv("BENCHITROOT");
 path=malloc(256);
 //sprintf(path,"%s/tools/hw_detect%s\0",root,script);
 sprintf(path,"%s\0",script);
 memset(output,0,buffersize);
 sysfs_argv=malloc((argc+3)*sizeof(char*));
 sysfs_argv[0]=(char*) malloc(4*sizeof(char)); sprintf(sysfs_argv[0],"sh\0");
 sysfs_argv[1]=(char*) malloc((2+strlen(path))*sizeof(char)); sprintf(sysfs_argv[1],"%s\0",path);
 for (i=0;i<argc;i++)
 {
   sysfs_argv[i+2]=args[i];
 }
 sysfs_argv[i+2]=NULL;

   if (pipe(fd)==-1)
   {
     if (DEBUG) perror("pipe");
     return -1;
   }
   pid=fork();
   if (pid==-1)
   {
    if (DEBUG) perror("fork");
    return -1;
   }
   if (pid==0)
   {
    close(fd[0]);
    dup2(fd[1],1);
    if (DEBUG) perror("dup2");
/*
    tmp=&path[strlen(path)-1];
    while (*tmp!='/') tmp--;
    *tmp='\0';
    chdir(path);
*/
    execvp("sh",sysfs_argv);
    if (DEBUG) perror("execvp");
    close(fd[1]);
    exit(0);//in case of errors
   }
   if (pid>0)
   {
    close(fd[1]);
    wait(&status);
    res=read(fd[0],output,MAX_OUTPUT-1);
    if ((res==-1)&&(DEBUG)) perror("read");
    else if (DEBUG) fprintf(stderr,"bytes read: %i\n",res);
    close(fd[0]);
   }

 tmp=strstr(output,"\n");
 while (tmp!=NULL)
 {
   *tmp='\0';
   tmp=strstr(output,"\n");
 }
 return 0;
}

int generic_num_packages()
{
  argv[0]=(char*)malloc(14*sizeof(char));sprintf(argv[0],"num_packages\0");
  if (sh("cpuinfo.sh",1,argv,output,MAX_OUTPUT)==-1) return -2;
  if (DEBUG) printf("num_packages output:%s\n",output);
  if (!strcmp(output,"n/a")) return -1;
  if (!strcmp(output,"")) return -1;
  if (atoi(output)<=0) return -1;
  return atoi(output);
}

int generic_num_cores_per_package()
{
  char* tmp;
  int num=0;
  argv[0]=(char*)malloc(14*sizeof(char));sprintf(argv[0],"cores_in_pkg\0");
  argv[1]=(char*)malloc(14*sizeof(char));sprintf(argv[1],"0\0");
  if (sh("cpuinfo.sh",2,argv,output,MAX_OUTPUT)==-1) return -2;
  if (!strcmp(output,"n/a")) return -1;
  if (!strcmp(output,"")) return -1;
  tmp=output;
  do
  {
   tmp=strstr(tmp,"core");
   if (tmp!=NULL) {tmp++;num++;}
  }
  while (tmp!=NULL);
                                     
  if (num==0) return -1;
  return num;
}

int generic_num_threads_per_core()
{
  char* tmp;
  int num=0;
        
  argv[0]=(char*)malloc(14*sizeof(char));sprintf(argv[0],"cpus_in_core\0");
  argv[1]=(char*)malloc(14*sizeof(char));sprintf(argv[1],"0\0");
  argv[2]=(char*)malloc(14*sizeof(char));sprintf(argv[2],"0\0");
  if (sh("cpuinfo.sh",3,argv,output,MAX_OUTPUT)==-1) return -2;
  if (DEBUG) printf("cpus_in_core output:%s\n",output);
  if (!strcmp(output,"n/a")) return -1;
  if (!strcmp(output,"")) return -1;
  tmp=output;
  do
  {
    tmp=strstr(tmp,"cpu");
    if (tmp!=NULL) {tmp++;num++;}
  }
  while (tmp!=NULL);
  if (num==0) num=generic_num_threads_per_package()/generic_num_cores_per_package();
  if (num!=generic_num_threads_per_package()/generic_num_cores_per_package()) return -1;
  return num;
}

int generic_num_threads_per_package()
{
 char* tmp;
 int num=0;

 argv[0]=(char*)malloc(14*sizeof(char));sprintf(argv[0],"cpus_in_pkg\0");
 argv[1]=(char*)malloc(14*sizeof(char));sprintf(argv[1],"0\0");
 if (sh("cpuinfo.sh",2,argv,output,MAX_OUTPUT)==-1) return -2;
 if (DEBUG) printf("cpus_in_pkg output:%s\n",output);
 if (!strcmp(output,"n/a")) return -1;
 if (!strcmp(output,"")) return -1;
 tmp=output;
 do
 {
   tmp=strstr(tmp,"cpu");
   if (tmp!=NULL) {tmp++;num++;}
 }
 while (tmp!=NULL);
               
 if (num==0) return -1;
 return num;
}
                                                        
unsigned int get_num_of_cores()
{
   return sysconf(_SC_NPROCESSORS_CONF);
}

#if defined (__x86_64__)

/**
 * measures latency of the timestampcounter
 * @return latency in cycles, 0 if not available
 */
static int get_rdtsc_latency_x86_64(cpu_info_t *cpuinfo)
{
   unsigned long long a,b;
   int latency=1000000,i;
   double tmp;

   if (!(cpuinfo->features&TSC)) return 0;

   /*
   * Output : RAX stop timestamp
   *          RBX start timestamp
   */
   for(i=0;i<100;i++)
   {
     __asm__ __volatile__(
                //start timestamp
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "mov %%rax,%%rbx;"
                //"rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                //"rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                //"rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                //"rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                //"rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                //"rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                //"rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                //"rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                //"rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                //"rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                //"rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                //"rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                //"rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                //"rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                //"rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                //"rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;rdtsc;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                //stop timestamp
                "rdtsc;shl $32,%%rdx;add %%rdx,%%rax;"
                : "=a" (a),"=b" (b)
                :
                : "%rdx"
          );

    tmp=rint(((double)(a-b))/((double)257));
    if (tmp<latency) latency=(int)tmp;
  }
  return latency;
}

static void cpuid(unsigned long long *a, unsigned long long *b, unsigned long long *c, unsigned long long *d)
{
  __asm__ __volatile__(
             "cpuid;"
           : "=a" (reg_a), "=b" (reg_b), "=c" (reg_c), "=d" (reg_d)
           : "a" (*a), "b" (*b), "c" (*c), "d" (*d)
     );
     *a=reg_a;
     *b=reg_b;
     *c=reg_c;
     *d=reg_d;
}

int get_cpu_vendor(char* vendor)
{
  a=0;
  cpuid(&a,&b,&c,&d);
  *((unsigned int*)&(vendor[0]))=(int)b;
  *((unsigned int*)&(vendor[4]))=(int)d;
  *((unsigned int*)&(vendor[8]))=(int)c;
  vendor[12]='\0';

  return 0;
}

static int has_rdtsc()
{
  a=0;
  cpuid(&a,&b,&c,&d);
  if (a>=1)
  {
    a=1;
    cpuid(&a,&b,&c,&d);
    if ((int)d&(1<<4)) return 1;
  }

  return 0;

}
static int scaling_governor(int cpu, char* output)
{
  if (cpu!=-1)
  {
     argv[0]=malloc(10*sizeof(char));
     argv[1]=malloc(20*sizeof(char));

     sprintf(argv[0],"cpu%i\0",cpu);
     sprintf(argv[1],"scaling_governor\0");
     if (sh("cpuinfo.sh",2,argv,output,MAX_OUTPUT))return -1;
     if(!strcmp(output,"n/a"))return -1;
     return 0;
  }
  else return -1;
}

int get_cpu_family()
 {
      a=0;
      cpuid(&a,&b,&c,&d);
      if (a>=1)
      {
        a=1;
        cpuid(&a,&b,&c,&d);

        return (((int)a>>8)&0xf)+(((int)a>>20)&0xff);
      }
      return -1;
 }

static int has_invariant_rdtsc()
{
   char tmp[MAX_OUTPUT];
   int res=0;

   if ((has_rdtsc())&&(get_cpu_vendor((char*)&tmp[0])==0))
   {

     /* TSCs are usable if CPU supports only one frequency in C0 (no speedstep/Cool'n'Quite) 
        or if multiple frequencies are available and the constant/invariant TSC feature flag is set */
      
      if (!strcmp(&tmp[0],"GenuineIntel"))
      {
         /*check if Powermanagement and invariant TSC are supported*/

           a=1;
           cpuid(&a,&b,&c,&d);
           /* no Frequency control */
           if ((!(d&(1<<22)))&&(!(c&(1<<7)))) res=1;
           a=0x80000000;
           cpuid(&a,&b,&c,&d);
           if (a >=0x80000007)
           {
              a=0x80000007;
              cpuid(&a,&b,&c,&d);
              /* invariant TSC */
              if (d&(1<<8)) res =1;
           }
         
      }

      if (!strcmp(&tmp[0],"AuthenticAMD"))
      {
         /*check if Powermanagement and invariant TSC are supported*/
 
           a=0x80000000;
           cpuid(&a,&b,&c,&d);
           if (a >=0x80000007)
           {
              a=0x80000007;
              cpuid(&a,&b,&c,&d);

              /* no Frequency control */
              if ((!(d&(1<<7)))&&(!(d&(1<<1)))) res=1;
              /* invariant TSC */
              if (d&(1<<8)) res =1;
              /* K8 TSCs can be used if a governor with fixed frequency is used */
              if (get_cpu_family()==15)
              {
                if (scaling_governor(0,tmp)==-1) res=1; /*assume no frequency control if sysfs does not contain governor information*/
                if (!strcmp(tmp,"performance")) res=1;
                if (!strcmp(tmp,"powersave")) res=1;
              }
           }
           /* assuming no frequency control if cpuid does not provide the extended function to test for it */
           else res=1;
         
      }
   }
   return res;
}

unsigned long long generic_get_cpu_clockrate(int cpu)
{
   argv[0]=(char*)malloc(14*sizeof(char));sprintf(argv[0],"cpu%i",cpu);
   argv[1]=(char*)malloc(14*sizeof(char));sprintf(argv[1],"max_freq",cpu);
   if (sh("cpuinfo.sh",2,argv,output,MAX_OUTPUT)==-1) return 0;
   if (!strcmp(output,"n/a")) return 0;
   else return (unsigned long long) atoll(output);
}

/**
 * measures latency of the timestampcounter
 * @return latency in cycles, 0 if not available
 */
static int get_clockrates_x86(cpu_info_t *cpuinfo)
{
  unsigned long long start1_tsc,start2_tsc,end1_tsc,end2_tsc;
  unsigned long long start_time,end_time;
  unsigned long long clock_lower_bound,clock_upper_bound,clock;
  int i,num_measurements=0;
  struct timeval timestamp;
   
  if (!has_rdtsc()) cpuinfo->clockrate=generic_get_cpu_clockrate(0);
  else if (!has_invariant_rdtsc()) cpuinfo->clockrate=generic_get_cpu_clockrate(0);
  else
  {
    //measure clockrate using tsc
    i=5;
    do
    {
      //start timestamp
      __asm__ __volatile__("rdtsc;": "=a" (start1_tsc):: "%rdx");
      gettimeofday(&timestamp,NULL);
      __asm__ __volatile__("rdtsc;": "=a" (start2_tsc):: "%rdx");

      start_time=timestamp.tv_sec*1000000+timestamp.tv_usec;

      //busy waiting
      usleep(400*i);

      //end timestamp
      __asm__ __volatile__("rdtsc;": "=a" (end1_tsc):: "%rdx");
      gettimeofday(&timestamp,NULL);
      __asm__ __volatile__("rdtsc;": "=a" (end2_tsc):: "%rdx");

      end_time=timestamp.tv_sec*1000000+timestamp.tv_usec;

      clock_lower_bound=((end1_tsc-start2_tsc)/(end_time-start_time))*1000000;
      clock_upper_bound=((end2_tsc-start1_tsc)/(end_time-start_time))*1000000;

      // if both values differ significantly, the measurement was interrupted between 2 rdtsc's
      if (((double)clock_lower_bound>(((double)clock_upper_bound)*0.999))&&((end_time-start_time)>2000))
      {
        num_measurements++;
        clock=(clock_lower_bound+clock_upper_bound)/2;
        if(cpuinfo->clockrate==0) cpuinfo->clockrate=clock;
        else if (clock<cpuinfo->clockrate) cpuinfo->clockrate=clock;
      }
      i++;
    }
    while (((end_time-start_time)<6000)||(num_measurements<10));
  }
  return 0;
}

#endif

/**
 * initializes cpuinfo-struct
 * @param print detection-summary is written to stdout when !=0
 */
void init_cpuinfo(cpu_info_t *cpuinfo,int print)
{
  int i,j;

  if (print) printf("\n  checking machine features:\n");fflush(stdout);

  cpuinfo->features=0;
  cpuinfo->clflush_linesize=0;
  cpuinfo->num_cores=0;
  cpuinfo->num_cores_per_package=0;
  cpuinfo->rdtsc_latency=0;
  cpuinfo->clockrate=0;
  cpuinfo->num_pagesizes=0;
  cpuinfo->virt_addr_length=0;
  cpuinfo->phys_addr_length=0;
  strcpy(cpuinfo->architecture,"unknown\0");
  strcpy(cpuinfo->vendor,"unknown\0");
  strcpy(cpuinfo->model_str,"unknown\0");

  for(i=0;i<MAX_CACHELEVELS;i++)
  {
      cpuinfo->Cache_shared[i]=0;
      cpuinfo->Cache_unified[i]=0;
      cpuinfo->I_Cache_Size[i]=0;
      cpuinfo->I_Cache_Sets[i]=0;
      cpuinfo->D_Cache_Size[i]=0;
      cpuinfo->D_Cache_Sets[i]=0;
      cpuinfo->U_Cache_Size[i]=0;
      cpuinfo->U_Cache_Sets[i]=0;
  }
  cpuinfo->Cachelevels=0;
  cpuinfo->Cacheflushsize=0;
  cpuinfo->Total_D_Cache_Size=0;
  cpuinfo->D_Cache_Size_per_Core=0;

  cpuinfo->tlblevels=0;

  for(i=0;i<MAX_TLBLEVELS;i++)
  {
    for(j=0;j<MAX_PAGESIZES;j++)
    {
      cpuinfo->I_TLB_Size[i][j]=0;
      cpuinfo->I_TLB_Sets[i][j]=0;
      cpuinfo->D_TLB_Size[i][j]=0;
      cpuinfo->D_TLB_Sets[i][j]=0;
      cpuinfo->U_TLB_Size[i][j]=0;
      cpuinfo->U_TLB_Sets[i][j]=0;
    }
  }


#if defined (__i386__)
/*
  supports 4K pages
  phys_addr_length 32 bits
  virt_addr_length 32 bits

  PSE -> 4M pages
  PAE -> 2M pages

  PSE36 -> phys_addr_length 36 bits

  wenn vorhandem CPUID F80000008 -> phys_addr_length
*/
#endif


  #if defined (__x86_64__)
  unsigned long long a=0,b=0,c=0,d=0;
  unsigned long long max,max_ext;
  int tmp;

  cpuinfo->num_cores=sysconf(_SC_NPROCESSORS_CONF);

  strcpy(cpuinfo->architecture,"x86_64\0");

  /* skipping eflags check as gnu assembler does not allow pushfd
    (however, as we are in 64bit mode we can assume to run on something newer than a 486)*/
 
  /*get vendor information*/
  __asm__ __volatile__(
             "mov $0,%%rax;"
             "cpuid;"
           : "=a" (a), "=b" (b), "=c" (c), "=d" (d)
           :
     );

  *((unsigned int*)&(cpuinfo->vendor[0]))=b;
  *((unsigned int*)&(cpuinfo->vendor[4]))=d;
  *((unsigned int*)&(cpuinfo->vendor[8]))=c;
  cpuinfo->vendor[12]='\0';
 
  cpuinfo->num_pagesizes=2;
  cpuinfo->pagesizes[0]=4096;
  cpuinfo->pagesizes[1]=2097152;

  if (!strcmp(cpuinfo->vendor,"AuthenticAMD"))
  {
    max=a;
    if (max>=0x00000001)
    {
      //get basic information  
      a=0x00000001;
      __asm__ __volatile__(
               "cpuid;"
            : "=a" (a), "=b" (b), "=c" (c), "=d" (d)
            : "a" (a)
        ); 

      cpuinfo->family=((a>>8)&0xf)+((a>>20)&0xff);
      cpuinfo->model=((a>>4)&0xf)+((a>>12)&0xf0);
      cpuinfo->stepping=(a&0xf);

      if (c&1) cpuinfo->features|=SSE3;
      if (c&(1<<3)) cpuinfo->features|=MONITOR;
      if (c&(1<<13)) cpuinfo->features|=CX16;
      if (c&(1<<23)) cpuinfo->features|=POPCNT;

      if (d&(1<<26)) cpuinfo->features|=SSE2;
      if (d&(1<<25)) cpuinfo->features|=SSE;
      if (d&(1<<23)) cpuinfo->features|=MMX;
      if (d&(1<<19)) cpuinfo->features|=CLFLUSH;
      if (d&(1<<12)) cpuinfo->features|=MTRR;
      if (d&(1<<8)) cpuinfo->features|=CX8;
      if (d&(1<<4)) cpuinfo->features|=TSC;
      if (d&(1<<4)) cpuinfo->features|=FPU;

      if(cpuinfo->features&CLFLUSH)  cpuinfo->clflush_linesize=((b>>8)&0xff)*8;

      if (d&(1<<28)) cpuinfo->num_cores_per_package=(b>>16)&0xff;
      else cpuinfo->num_cores_per_package=1;
    }

     a=0x80000000;   
     __asm__ __volatile__(
                "cpuid;"
              : "=a" (a), "=b" (b), "=c" (c), "=d" (d)
              : "a" (a)
        );
     if (a&0x80000000) max_ext=a; else max_ext=0;

     if(max_ext>=0x80000001)
     {
      a=0x80000001;
      __asm__ __volatile__(
                "cpuid;"
              : "=a" (a), "=b" (b), "=c" (c), "=d" (d)
              : "a" (a)
       );
       if (c&(1<<6)) cpuinfo->features|=SSE4A;
       if (c&(1<<5)) cpuinfo->features|=ABM;
       if (d&(1<<29)) cpuinfo->features|=X86_64;
       if (d&(1<<20)) cpuinfo->features|=NX;
       if (d&(1<<22)) cpuinfo->features|=MMX_EXT;
       if (d&(1<<31)) cpuinfo->features|=_3DNOW;
       if (d&(1<<30)) cpuinfo->features|=_3DNOW_EXT;

       if (d&(1<<26))
       {
           cpuinfo->pagesizes[cpuinfo->num_pagesizes]=1024*1048576;
           cpuinfo->num_pagesizes++;
       }
     }
     //read the processor name string if available   
     if(max_ext>=0x80000004)
     {
      a=0x80000002;   
      __asm__ __volatile__(
                "cpuid;"
              : "=a" (a), "=b" (b), "=c" (c), "=d" (d)
              : "a" (a)
       );
      *((unsigned int*)&(cpuinfo->model_str[0]))=a;
      *((unsigned int*)&(cpuinfo->model_str[4]))=b;
      *((unsigned int*)&(cpuinfo->model_str[8]))=c;
      *((unsigned int*)&(cpuinfo->model_str[12]))=d;
      a=0x80000003;   
      __asm__ __volatile__(
                "cpuid;"
              : "=a" (a), "=b" (b), "=c" (c), "=d" (d)
              : "a" (a)
       );
      *((unsigned int*)&(cpuinfo->model_str[16]))=a;
      *((unsigned int*)&(cpuinfo->model_str[20]))=b;
      *((unsigned int*)&(cpuinfo->model_str[24]))=c;
      *((unsigned int*)&(cpuinfo->model_str[28]))=d;
      a=0x80000004;   
      __asm__ __volatile__(
                "cpuid;"
              : "=a" (a), "=b" (b), "=c" (c), "=d" (d)
              : "a" (a)
       );
      *((unsigned int*)&(cpuinfo->model_str[32]))=a;
      *((unsigned int*)&(cpuinfo->model_str[36]))=b;
      *((unsigned int*)&(cpuinfo->model_str[40]))=c;
      *((unsigned int*)&(cpuinfo->model_str[44]))=d;
     }
     else strcpy(cpuinfo->model_str,"unknown\0");

     if(max_ext>=0x80000005)
     {
      a=0x80000005;
      __asm__ __volatile__(
                "cpuid;"
              : "=a" (a), "=b" (b), "=c" (c), "=d" (d)
              : "a" (a)
       );

       cpuinfo->D_TLB_Size[0][1]=(a>>16)&0xff;
       cpuinfo->D_TLB_Sets[0][1]=(a>>24)&0xff;
       if (cpuinfo->D_TLB_Sets[0][1]==0xff) cpuinfo->D_TLB_Sets[0][1]=0;
       cpuinfo->I_TLB_Size[0][1]=a&0xff;
       cpuinfo->I_TLB_Sets[0][1]=(a>>8)&0xff;
       if (cpuinfo->I_TLB_Sets[0][1]==0xff) cpuinfo->I_TLB_Sets[0][1]=0;

       if (cpuinfo->D_TLB_Size[0][1]+cpuinfo->I_TLB_Size[0][1]) cpuinfo->tlblevels=1;

       cpuinfo->D_TLB_Size[0][0]=(b>>16)&0xff;
       cpuinfo->D_TLB_Sets[0][0]=(b>>24)&0xff;
       if (cpuinfo->D_TLB_Sets[0][0]==0xff) cpuinfo->D_TLB_Sets[0][0]=0;
       cpuinfo->I_TLB_Size[0][0]=b&0xff;
       cpuinfo->I_TLB_Sets[0][0]=b>>8&0xff;
       if (cpuinfo->I_TLB_Sets[0][0]==0xff) cpuinfo->I_TLB_Sets[0][0]=0;

       if (cpuinfo->D_TLB_Size[0][0]+cpuinfo->I_TLB_Size[0][0]) cpuinfo->tlblevels=1;

       cpuinfo->Cache_unified[0]=0;
       cpuinfo->Cache_shared[0]=1;
       cpuinfo->D_Cache_Size[0]=(c>>24)*1024;
       cpuinfo->D_Cache_Sets[0]=(c>>16)&0xff;
       if (cpuinfo->D_Cache_Sets[0]==0xff) cpuinfo->D_Cache_Sets[0]=0;
       cpuinfo->I_Cache_Size[0]=(d>>24)*1024;
       cpuinfo->I_Cache_Sets[0]=(d>>16)&0xff;
       if (cpuinfo->I_Cache_Sets[0]==0xff) cpuinfo->I_Cache_Sets[0]=0;
       cpuinfo->Cacheline_size[0]=c&0xff;
       if (d&0xff<cpuinfo->Cacheline_size[0]) cpuinfo->Cacheline_size[0]=d&0xff;
       if (cpuinfo->D_Cache_Size[0]+cpuinfo->I_Cache_Size[0]>0) cpuinfo->Cachelevels=1;
       cpuinfo->Cacheflushsize+=cpuinfo->D_Cache_Size[0];
       cpuinfo->Total_D_Cache_Size+=(cpuinfo->num_cores/cpuinfo->Cache_shared[0])*cpuinfo->D_Cache_Size[0];
       cpuinfo->D_Cache_Size_per_Core+=cpuinfo->D_Cache_Size[0];
     }

     if(max_ext>=0x80000006)
     {
      a=0x80000006;
      __asm__ __volatile__(
                "cpuid;"
              : "=a" (a), "=b" (b), "=c" (c), "=d" (d)
              : "a" (a)
       );

       if (((a&0xffff0000)==0)&&((b&0xffff0000)==0))
       {
         cpuinfo->U_TLB_Size[1][1]=a&0xfff;
         cpuinfo->U_TLB_Sets[1][1]=(a>>12)&0xf;
         switch (cpuinfo->U_TLB_Sets[1][1])
         {
           case 0x0: cpuinfo->U_TLB_Size[1][1]=0;cpuinfo->U_TLB_Sets[1][1]=0;break;
           case 0x6: cpuinfo->U_TLB_Sets[1][1]=8;break;
           case 0x8: cpuinfo->U_TLB_Sets[1][1]=16;break;
           case 0xa: cpuinfo->U_TLB_Sets[1][1]=32;break;
           case 0xb: cpuinfo->U_TLB_Sets[1][1]=48;break;
           case 0xc: cpuinfo->U_TLB_Sets[1][1]=64;break;
           case 0xd: cpuinfo->U_TLB_Sets[1][1]=96;break;
           case 0xe: cpuinfo->U_TLB_Sets[1][1]=128;break;
           case 0xf: cpuinfo->U_TLB_Sets[1][1]=0;break;
         }

         if (cpuinfo->U_TLB_Size[1][1]) cpuinfo->tlblevels=2;

         cpuinfo->U_TLB_Size[1][0]=b&0xfff;
         cpuinfo->U_TLB_Sets[1][0]=(b>>12)&0xf;
         switch (cpuinfo->U_TLB_Sets[1][0])
         {
           case 0x0: cpuinfo->U_TLB_Size[1][0]=0;cpuinfo->U_TLB_Sets[1][0]=0;break;
           case 0x6: cpuinfo->U_TLB_Sets[1][0]=8;break;
           case 0x8: cpuinfo->U_TLB_Sets[1][0]=16;break;
           case 0xa: cpuinfo->U_TLB_Sets[1][0]=32;break;
           case 0xb: cpuinfo->U_TLB_Sets[1][0]=48;break;
           case 0xc: cpuinfo->U_TLB_Sets[1][0]=64;break;
           case 0xd: cpuinfo->U_TLB_Sets[1][0]=96;break;
           case 0xe: cpuinfo->U_TLB_Sets[1][0]=128;break;
           case 0xf: cpuinfo->U_TLB_Sets[1][0]=0;break;
         }

         if (cpuinfo->U_TLB_Size[1][0]) cpuinfo->tlblevels=2;
       }
       else
       {
         cpuinfo->D_TLB_Size[1][1]=(a>>16)&0xfff;
         cpuinfo->D_TLB_Sets[1][1]=(a>>28)&0xf;
         switch (cpuinfo->D_TLB_Sets[1][1])
         {
           case 0x0: cpuinfo->D_TLB_Size[1][1]=0;cpuinfo->D_TLB_Sets[1][1]=0;break;
           case 0x6: cpuinfo->D_TLB_Sets[1][1]=8;break;
           case 0x8: cpuinfo->D_TLB_Sets[1][1]=16;break;
           case 0xa: cpuinfo->D_TLB_Sets[1][1]=32;break;
           case 0xb: cpuinfo->D_TLB_Sets[1][1]=48;break;
           case 0xc: cpuinfo->D_TLB_Sets[1][1]=64;break;
           case 0xd: cpuinfo->D_TLB_Sets[1][1]=96;break;
           case 0xe: cpuinfo->D_TLB_Sets[1][1]=128;break;
           case 0xf: cpuinfo->D_TLB_Sets[1][1]=0;break;
         }
         cpuinfo->I_TLB_Size[1][1]=a&0xfff;
         cpuinfo->I_TLB_Sets[1][1]=(a>>12)&0xf;
         switch (cpuinfo->I_TLB_Sets[1][1])
         {
           case 0x0: cpuinfo->I_TLB_Size[1][1]=0;cpuinfo->I_TLB_Sets[1][1]=0;break;
           case 0x6: cpuinfo->I_TLB_Sets[1][1]=8;break;
           case 0x8: cpuinfo->I_TLB_Sets[1][1]=16;break;
           case 0xa: cpuinfo->I_TLB_Sets[1][1]=32;break;
           case 0xb: cpuinfo->I_TLB_Sets[1][1]=48;break;
           case 0xc: cpuinfo->I_TLB_Sets[1][1]=64;break;
           case 0xd: cpuinfo->I_TLB_Sets[1][1]=96;break;
           case 0xe: cpuinfo->I_TLB_Sets[1][1]=128;break;
           case 0xf: cpuinfo->I_TLB_Sets[1][1]=0;break;
         }

         if (cpuinfo->D_TLB_Size[1][1]+cpuinfo->I_TLB_Size[1][1]) cpuinfo->tlblevels=2;

         cpuinfo->D_TLB_Size[1][0]=(b>>16)&0xfff;
         cpuinfo->D_TLB_Sets[1][0]=(b>>28)&0xf;
         switch (cpuinfo->D_TLB_Sets[1][0])
         {
           case 0x0: cpuinfo->D_TLB_Size[1][0]=0;cpuinfo->D_TLB_Sets[1][0]=0;break;
           case 0x6: cpuinfo->D_TLB_Sets[1][0]=8;break;
           case 0x8: cpuinfo->D_TLB_Sets[1][0]=16;break;
           case 0xa: cpuinfo->D_TLB_Sets[1][0]=32;break;
           case 0xb: cpuinfo->D_TLB_Sets[1][0]=48;break;
           case 0xc: cpuinfo->D_TLB_Sets[1][0]=64;break;
           case 0xd: cpuinfo->D_TLB_Sets[1][0]=96;break;
           case 0xe: cpuinfo->D_TLB_Sets[1][0]=128;break;
           case 0xf: cpuinfo->D_TLB_Sets[1][0]=0;break;
         }
         cpuinfo->I_TLB_Size[1][0]=b&0xfff;
         cpuinfo->I_TLB_Sets[1][0]=(b>>8)&0xf;
         switch (cpuinfo->I_TLB_Sets[1][0])
         {
           case 0x0: cpuinfo->I_TLB_Size[1][0]=0;cpuinfo->I_TLB_Sets[1][0]=0;break;
           case 0x6: cpuinfo->I_TLB_Sets[1][0]=8;break;
           case 0x8: cpuinfo->I_TLB_Sets[1][0]=16;break;
           case 0xa: cpuinfo->I_TLB_Sets[1][0]=32;break;
           case 0xb: cpuinfo->I_TLB_Sets[1][0]=48;break;
           case 0xc: cpuinfo->I_TLB_Sets[1][0]=64;break;
           case 0xd: cpuinfo->I_TLB_Sets[1][0]=96;break;
           case 0xe: cpuinfo->I_TLB_Sets[1][0]=128;break;
           case 0xf: cpuinfo->I_TLB_Sets[1][0]=0;break;
         }

         if (cpuinfo->D_TLB_Size[1][0]+cpuinfo->I_TLB_Size[1][0]) cpuinfo->tlblevels=2;
       }

       cpuinfo->Cache_unified[1]=1;
       cpuinfo->Cache_shared[1]=1;
       cpuinfo->U_Cache_Size[1]=(c>>16)*1024;
       cpuinfo->U_Cache_Sets[1]=(c>>12)&0xf;

       switch (cpuinfo->U_Cache_Sets[1])
       {
           case 0x0: cpuinfo->U_Cache_Size[1]=0;cpuinfo->U_Cache_Sets[1]=0;break;
           case 0x6: cpuinfo->U_Cache_Sets[1]=8;break;
           case 0x8: cpuinfo->U_Cache_Sets[1]=16;break;
           case 0xa: cpuinfo->U_Cache_Sets[1]=32;break;
           case 0xb: cpuinfo->U_Cache_Sets[1]=48;break;
           case 0xc: cpuinfo->U_Cache_Sets[1]=64;break;
           case 0xd: cpuinfo->U_Cache_Sets[1]=96;break;
           case 0xe: cpuinfo->U_Cache_Sets[1]=128;break;
           case 0xf: cpuinfo->U_Cache_Sets[1]=0;break;

       }

       cpuinfo->Cacheline_size[1]=c&0xff;
       if (cpuinfo->U_Cache_Size[1]>0) cpuinfo->Cachelevels=2;
       cpuinfo->Cacheflushsize+=cpuinfo->U_Cache_Size[1];
       cpuinfo->Total_D_Cache_Size+=(cpuinfo->num_cores/cpuinfo->Cache_shared[1])*cpuinfo->U_Cache_Size[1];
       cpuinfo->D_Cache_Size_per_Core+=cpuinfo->U_Cache_Size[1];

       cpuinfo->Cache_unified[2]=1;
       cpuinfo->Cache_shared[2]=cpuinfo->num_cores_per_package;
       cpuinfo->U_Cache_Size[2]=(d>>18)*524288;
       cpuinfo->U_Cache_Sets[2]=(d>>12)&0xf;

       switch (cpuinfo->U_Cache_Sets[2])
       {
           case 0x0: cpuinfo->U_Cache_Size[2]=0;cpuinfo->U_Cache_Sets[2]=0;break;
           case 0x6: cpuinfo->U_Cache_Sets[2]=8;break;
           case 0x8: cpuinfo->U_Cache_Sets[2]=16;break;
           case 0xa: cpuinfo->U_Cache_Sets[2]=32;break;
           case 0xb: cpuinfo->U_Cache_Sets[2]=48;break;
           case 0xc: cpuinfo->U_Cache_Sets[2]=64;break;
           case 0xd: cpuinfo->U_Cache_Sets[2]=96;break;
           case 0xe: cpuinfo->U_Cache_Sets[2]=128;break;
           case 0xf: cpuinfo->U_Cache_Sets[2]=0;break;

       }

       cpuinfo->Cacheline_size[2]=d&0xff;
       if (cpuinfo->U_Cache_Size[2]>0) cpuinfo->Cachelevels=3;
       cpuinfo->Cacheflushsize+=cpuinfo->U_Cache_Size[2];
       cpuinfo->Total_D_Cache_Size+=(cpuinfo->num_cores/cpuinfo->Cache_shared[2])*cpuinfo->U_Cache_Size[2];
       cpuinfo->D_Cache_Size_per_Core+=cpuinfo->U_Cache_Size[2];
     }

     if(max_ext>=0x80000007)
     {
      a=0x80000007;
      __asm__ __volatile__(
                "cpuid;"
              : "=a" (a), "=b" (b), "=c" (c), "=d" (d)
              : "a" (a)
       );
       if ((d&(1<<7))||(d&(1<<1))) cpuinfo->features|=FREQ_SCALING;
     }

     if(max_ext>=0x80000008)
     {
      a=0x80000008;
      __asm__ __volatile__(
                "cpuid;"
              : "=a" (a), "=b" (b), "=c" (c), "=d" (d)
              : "a" (a)
       );
       cpuinfo->phys_addr_length=a&0xff;
       cpuinfo->virt_addr_length=(a>>8)&0xff;
     }
     if((max_ext>=0x80000019)&&(cpuinfo->num_pagesizes>=3))
     {
      a=0x80000019;
      __asm__ __volatile__(
                "cpuid;"
              : "=a" (a), "=b" (b), "=c" (c), "=d" (d)
              : "a" (a)
       );
         cpuinfo->D_TLB_Size[0][2]=(a>>16)&0xfff;
         cpuinfo->D_TLB_Sets[0][2]=(a>>28)&0xf;
         switch (cpuinfo->D_TLB_Sets[0][2])
         {
           case 0x0: cpuinfo->D_TLB_Size[0][2]=0;cpuinfo->D_TLB_Sets[0][2]=0;break;
           case 0x6: cpuinfo->D_TLB_Sets[0][2]=8;break;
           case 0x8: cpuinfo->D_TLB_Sets[0][2]=16;break;
           case 0xa: cpuinfo->D_TLB_Sets[0][2]=32;break;
           case 0xb: cpuinfo->D_TLB_Sets[0][2]=48;break;
           case 0xc: cpuinfo->D_TLB_Sets[0][2]=64;break;
           case 0xd: cpuinfo->D_TLB_Sets[0][2]=96;break;
           case 0xe: cpuinfo->D_TLB_Sets[0][2]=128;break;
           case 0xf: cpuinfo->D_TLB_Sets[0][2]=0;break;
         }
         cpuinfo->I_TLB_Size[0][2]=a&0xfff;
         cpuinfo->I_TLB_Sets[0][2]=(a>>12)&0xf;
         switch (cpuinfo->I_TLB_Sets[0][2])
         {
           case 0x0: cpuinfo->I_TLB_Size[0][2]=0;cpuinfo->I_TLB_Sets[0][2]=0;break;
           case 0x6: cpuinfo->I_TLB_Sets[0][2]=8;break;
           case 0x8: cpuinfo->I_TLB_Sets[0][2]=16;break;
           case 0xa: cpuinfo->I_TLB_Sets[0][2]=32;break;
           case 0xb: cpuinfo->I_TLB_Sets[0][2]=48;break;
           case 0xc: cpuinfo->I_TLB_Sets[0][2]=64;break;
           case 0xd: cpuinfo->I_TLB_Sets[0][2]=96;break;
           case 0xe: cpuinfo->I_TLB_Sets[0][2]=128;break;
           case 0xf: cpuinfo->I_TLB_Sets[0][2]=0;break;
         }

         if ((cpuinfo->D_TLB_Size[0][2]+cpuinfo->I_TLB_Size[0][2])&&(cpuinfo->tlblevels<1)) cpuinfo->tlblevels=1;

         cpuinfo->D_TLB_Size[1][2]=(b>>16)&0xfff;
         cpuinfo->D_TLB_Sets[1][2]=(b>>28)&0xf;
         switch (cpuinfo->D_TLB_Sets[1][2])
         {
           case 0x0: cpuinfo->D_TLB_Size[1][2]=0;cpuinfo->D_TLB_Sets[1][2]=0;break;
           case 0x6: cpuinfo->D_TLB_Sets[1][2]=8;break;
           case 0x8: cpuinfo->D_TLB_Sets[1][2]=16;break;
           case 0xa: cpuinfo->D_TLB_Sets[1][2]=32;break;
           case 0xb: cpuinfo->D_TLB_Sets[1][2]=48;break;
           case 0xc: cpuinfo->D_TLB_Sets[1][2]=64;break;
           case 0xd: cpuinfo->D_TLB_Sets[1][2]=96;break;
           case 0xe: cpuinfo->D_TLB_Sets[1][2]=128;break;
           case 0xf: cpuinfo->D_TLB_Sets[1][2]=0;break;
         }
         cpuinfo->I_TLB_Size[1][2]=b&0xfff;
         cpuinfo->I_TLB_Sets[1][2]=(b>>8)&0xf;
         switch (cpuinfo->I_TLB_Sets[1][2])
         {
           case 0x0: cpuinfo->I_TLB_Size[1][2]=0;cpuinfo->I_TLB_Sets[1][2]=0;break;
           case 0x6: cpuinfo->I_TLB_Sets[1][2]=8;break;
           case 0x8: cpuinfo->I_TLB_Sets[1][2]=16;break;
           case 0xa: cpuinfo->I_TLB_Sets[1][2]=32;break;
           case 0xb: cpuinfo->I_TLB_Sets[1][2]=48;break;
           case 0xc: cpuinfo->I_TLB_Sets[1][2]=64;break;
           case 0xd: cpuinfo->I_TLB_Sets[1][2]=96;break;
           case 0xe: cpuinfo->I_TLB_Sets[1][2]=128;break;
           case 0xf: cpuinfo->I_TLB_Sets[1][2]=0;break;
         }

         if ((cpuinfo->D_TLB_Size[1][2]+cpuinfo->I_TLB_Size[1][2])&&(cpuinfo->tlblevels<2)) cpuinfo->tlblevels=2;
     }
  }
  if (!strcmp(cpuinfo->vendor,"GenuineIntel"))
  { 
    max=a;
    if (max>=0x00000001)
    {
      //get basic information  
      a=0x00000001;
      __asm__ __volatile__(
               "cpuid;"
            : "=a" (a), "=b" (b), "=c" (c), "=d" (d)
            : "a" (a)
        ); 

      cpuinfo->family=((a>>8)&0xf);
      cpuinfo->model=((a>>4)&0xf);
      cpuinfo->stepping=(a&0xf);

      if((cpuinfo->family==0xf)||(cpuinfo->family==0x6)) cpuinfo->model+=((a>>12)&0xf0);
      if(cpuinfo->family==0xf) cpuinfo->family+=((a>>20)&0xff);

      if (c&1) cpuinfo->features|=SSE3;
      if (c&(1<<3)) cpuinfo->features|=MONITOR;
      if (c&(1<<7)) cpuinfo->features|=FREQ_SCALING;
      if (c&(1<<9)) cpuinfo->features|=SSSE3;
      if (c&(1<<13)) cpuinfo->features|=CX16;
      if (c&(1<<19)) cpuinfo->features|=SSE4_1;
      if (c&(1<<20)) cpuinfo->features|=SSE4_2;
      if (c&(1<<23)) cpuinfo->features|=POPCNT;

      if (d&(1<<26)) cpuinfo->features|=SSE2;
      if (d&(1<<25)) cpuinfo->features|=SSE;
      if (d&(1<<23)) cpuinfo->features|=MMX;
      if (d&(1<<19)) cpuinfo->features|=CLFLUSH;
      if (d&(1<<12)) cpuinfo->features|=MTRR;
      if (d&(1<<8)) cpuinfo->features|=CX8;
      if (d&(1<<4)) cpuinfo->features|=TSC;
      if (d&(1<<4)) cpuinfo->features|=FPU;

      if(cpuinfo->features&CLFLUSH)  cpuinfo->clflush_linesize=((b>>8)&0xff)*8;
      cpuinfo->num_cores_per_package=generic_num_cores_per_package();

      if (cpuinfo->num_cores_per_package==-1)
      {
        if (d&(1<<28)) cpuinfo->num_cores_per_package=(b>>16)&0xff;
        else cpuinfo->num_cores_per_package=1; 
      }
    }
    if (max>=0x00000002)
    {
      int descriptors[15];
      a=0x00000002;
      i=0;
      do
      {
        i++;
        __asm__ __volatile__(
               "cpuid;"
            : "=a" (a), "=b" (b), "=c" (c), "=d" (d)
            : "a" (a)
        );

        for (j=1;j<4;j++) descriptors[j-1]=(a>>(8*j))&0xff;
        for (j=0;j<4;j++)
        {
          descriptors[j+3]=(b>>(8*j))&0xff;
          descriptors[j+7]=(c>>(8*j))&0xff;
          descriptors[j+11]=(d>>(8*j))&0xff;
        }
        for (j=0;j<15;j++)
        {
            switch(descriptors[j])
            {
                case 0x00: break;

                /*TODO P4 L1 instruction trace cache*/
                case 0x70: /*12K µops, 8-way*/ break;
                case 0x71: /*16K µops, 8-way*/ break;
                case 0x72: /*32K µops, 8-way*/ break;
                case 0x73: /*64K µops, 8-way*/ break;

                /*TODO prefetching*/
                case 0xf0: /*64-Byte prefetching*/ break;
                case 0xf1: /*128-Byte prefetching*/ break;

                /*caches are estimated using CPUID 04h*/
                case 0x06: break;
                case 0x08: break;
                case 0x0a: break;
                case 0x0c: break;
                case 0x22: break;
                case 0x23: break;
                case 0x25: break;
                case 0x29: break;
                case 0x2c: break;
                case 0x30: break;
                case 0x39: break;
                case 0x3a: break;
                case 0x3b: break;
                case 0x3c: break;
                case 0x3d: break;
                case 0x3e: break;
                case 0x40: break;
                case 0x41: break;
                case 0x42: break;
                case 0x43: break;
                case 0x44: break;
                case 0x45: break;
                case 0x46: break;
                case 0x47: break;
                case 0x49: break;
                case 0x4a: break;
                case 0x4b: break;
                case 0x4c: break;
                case 0x4d: break;
                case 0x4e: break;
                case 0x60: break;
                case 0x66: break;
                case 0x67: break;
                case 0x68: break;
                case 0x78: break;
                case 0x79: break;
                case 0x7a: break;
                case 0x7b: break;
                case 0x7c: break;
                case 0x7d: break;
                case 0x7f: break;
                case 0x82: break;
                case 0x83: break;
                case 0x84: break;
                case 0x85: break;
                case 0x86: break;
                case 0x87: break;
                case 0x09: break;
                case 0xe4: break;
                case 0x21: break;
                

                /*Intel TLB definitions*/
                /*[level][pagesize] pagesize: 0-> 4K,1 ->2M*/ 
                case 0x01: if(cpuinfo->tlblevels<2)cpuinfo->tlblevels=2;
                           cpuinfo->I_TLB_Size[1][0]=32;
                           cpuinfo->I_TLB_Sets[1][0]=4;
                           break;
                case 0x02: if(cpuinfo->tlblevels<2)cpuinfo->tlblevels=2; 
                           cpuinfo->I_TLB_Size[1][1]=4; //2 4M
                           cpuinfo->I_TLB_Sets[1][1]=0; //4-way
                           break;
                case 0x03: if(cpuinfo->tlblevels<2)cpuinfo->tlblevels=2;
                           cpuinfo->D_TLB_Size[1][0]=64;
                           cpuinfo->D_TLB_Sets[1][0]=4;
                           break;
                case 0x04: if(cpuinfo->tlblevels<2)cpuinfo->tlblevels=2;
                           cpuinfo->D_TLB_Size[1][1]=16; //8 4M
                           cpuinfo->D_TLB_Sets[1][1]=4;
                           break;
                case 0x05: if(cpuinfo->tlblevels<2)cpuinfo->tlblevels=2;
                           cpuinfo->D_TLB_Size[1][1]=64; //32 4M 
                           cpuinfo->D_TLB_Sets[1][1]=4;
                           break;
                case 0x0b: if(cpuinfo->tlblevels<2)cpuinfo->tlblevels=2;
                           cpuinfo->I_TLB_Size[1][1]=8; //4 4M
                           cpuinfo->I_TLB_Sets[1][1]=4; 
                           break;

                case 0x50: if(cpuinfo->tlblevels<2)cpuinfo->tlblevels=2;
                           cpuinfo->I_TLB_Size[1][0]=64;
                           cpuinfo->I_TLB_Sets[1][0]=0;
                           break;
                case 0x51: if(cpuinfo->tlblevels<2)cpuinfo->tlblevels=2;
                           cpuinfo->I_TLB_Size[1][0]=128;
                           cpuinfo->I_TLB_Sets[1][0]=0;
                           break;
                case 0x52: if(cpuinfo->tlblevels<2)cpuinfo->tlblevels=2;
                           cpuinfo->I_TLB_Size[1][0]=256;
                           cpuinfo->I_TLB_Sets[1][0]=0;
                           break;

                case 0x56: if(cpuinfo->tlblevels<1)cpuinfo->tlblevels=1;
                           cpuinfo->D_TLB_Size[0][1]=32; //16 4M 
                           cpuinfo->D_TLB_Sets[0][1]=4;
                           break;
                case 0x57: if(cpuinfo->tlblevels<1)cpuinfo->tlblevels=1;
                           cpuinfo->D_TLB_Size[0][0]=16;
                           cpuinfo->D_TLB_Sets[0][0]=4;
                           break;

                case 0x5b: if(cpuinfo->tlblevels<2)cpuinfo->tlblevels=2;
                           cpuinfo->D_TLB_Size[1][0]=64;
                           cpuinfo->D_TLB_Sets[1][0]=0;
                           break;
                case 0x5c: if(cpuinfo->tlblevels<2)cpuinfo->tlblevels=2;
                           cpuinfo->D_TLB_Size[1][0]=128;
                           cpuinfo->D_TLB_Sets[1][0]=0;
                           break;
                case 0x5d: if(cpuinfo->tlblevels<2)cpuinfo->tlblevels=2;
                           cpuinfo->D_TLB_Size[1][0]=256;
                           cpuinfo->D_TLB_Sets[1][0]=0;
                           break;

                case 0xb0: if(cpuinfo->tlblevels<2)cpuinfo->tlblevels=2;
                           cpuinfo->I_TLB_Size[1][0]=128;
                           cpuinfo->I_TLB_Sets[1][0]=4;
                           break;
                case 0xb1: if(cpuinfo->tlblevels<2)cpuinfo->tlblevels=2;
                           cpuinfo->I_TLB_Size[1][1]=8;
                           cpuinfo->I_TLB_Sets[1][1]=4;
                           break;
                case 0xb3: if(cpuinfo->tlblevels<2)cpuinfo->tlblevels=2;
                           cpuinfo->D_TLB_Size[1][0]=128;
                           cpuinfo->D_TLB_Sets[1][0]=4;
                           break;
                case 0xb4: if(cpuinfo->tlblevels<2)cpuinfo->tlblevels=2;
                           cpuinfo->D_TLB_Size[1][0]=256;
                           cpuinfo->D_TLB_Sets[1][0]=4;
                           break;
                case 0xca: if(cpuinfo->tlblevels<3)cpuinfo->tlblevels=3;
                           cpuinfo->D_TLB_Size[2][0]=512;
                           cpuinfo->D_TLB_Sets[2][0]=4;
                           break;
                case 0x5a: if(cpuinfo->tlblevels<2)cpuinfo->tlblevels=2;
                           cpuinfo->D_TLB_Size[1][1]=32; //16 4M
                           cpuinfo->D_TLB_Sets[1][1]=4;
                           break;
                case 0x55: if(cpuinfo->tlblevels<2)cpuinfo->tlblevels=2;
                           cpuinfo->I_TLB_Size[1][1]=7;
                           cpuinfo->I_TLB_Sets[1][1]=0;
                           break;
                default: if (print) 
                         {
                            printf("\n");
                            printf("    WARNING: CPUID Function 02h returned unknown Cache/TLB-descriptor \"%02xh\"\n",descriptors[j]);
                            printf("             update \"/*Intel TLB definitions*/\" in \"arch.c\" with the latest Intel cpuid-specification\n");
                            printf("\n");
                         }
                         break;

            }
        }
      }
      while(i<(a&0xff));

    }

    if (max>=0x00000004)
    {
      i=0;
      do
      {
         a=0x00000004;c=(unsigned long long)i;
         __asm__ __volatile__(
                  "cpuid;"
                : "=a" (a), "=b" (b), "=c" (c), "=d" (d)
                : "a" (a), "c" (c)
         );
         tmp=((a&0xe0)>>5)-1;
         if ((tmp>=0)&&(tmp<MAX_CACHELEVELS))
         {
             cpuinfo->Cache_shared[tmp]=((a&0x03ffc000)>>14)+1;
             
             /* Hyperthreading */
             if (cpuinfo->family==15) cpuinfo->Cache_shared[tmp]=generic_num_threads_per_core();
             if ((cpuinfo->family==6)&&(cpuinfo->model==26))
             {
              //TODO fix!!!
              if (tmp<2) cpuinfo->Cache_shared[tmp]=generic_num_threads_per_core();
              if (tmp==2) cpuinfo->Cache_shared[tmp]=generic_num_threads_per_package();
              //cpuinfo->num_cores_per_package=4;
             }
             if ((cpuinfo->family==6)&&(cpuinfo->model==28)) cpuinfo->Cache_shared[tmp]=generic_num_threads_per_core();
             
             if (cpuinfo->Cache_shared[tmp]==-1) cpuinfo->Cache_shared[tmp]=1;
             
             cpuinfo->Cacheline_size[tmp]=((b&0x0fff)+1);
             if ((tmp+1)>cpuinfo->Cachelevels) cpuinfo->Cachelevels=tmp+1;
             if ((a&0x1f)==1)
             { 
                cpuinfo->I_Cache_Size[tmp]=(((b&0xffc00000)>>22)+1)*(c+1)*((b&0x0fff)+1);
                if (a&0x200) cpuinfo->I_Cache_Sets[tmp]=0; else cpuinfo->I_Cache_Sets[tmp]=((b&0xffc00000)>>22)+1;
             }
             if ((a&0x1f)==2)
             { 
                cpuinfo->D_Cache_Size[tmp]=(((b&0xffc00000)>>22)+1)*(c+1)*((b&0x0fff)+1);
                if (a&0x200) cpuinfo->D_Cache_Sets[tmp]=0; else cpuinfo->D_Cache_Sets[tmp]=((b&0xffc00000)>>22)+1;
                cpuinfo->Cacheflushsize+=cpuinfo->D_Cache_Size[tmp];
       		//cpuinfo->Total_D_Cache_Size+=(cpuinfo->num_cores/cpuinfo->Cache_shared[tmp])*cpuinfo->D_Cache_Size[tmp];
       		cpuinfo->Total_D_Cache_Size=(cpuinfo->num_cores/cpuinfo->Cache_shared[tmp])*cpuinfo->D_Cache_Size[tmp];//inclusive
		//cpuinfo->D_Cache_Size_per_Core+=cpuinfo->D_Cache_Size[tmp];
		cpuinfo->D_Cache_Size_per_Core=cpuinfo->D_Cache_Size[tmp];//inclusive
             }
             if ((a&0x1f)==3)
             { 
                cpuinfo->Cache_unified[tmp]=1;
                cpuinfo->U_Cache_Size[tmp]=(((b&0xffc00000)>>22)+1)*(c+1)*((b&0x0fff)+1);
                if (a&0x200) cpuinfo->U_Cache_Sets[tmp]=0; else cpuinfo->U_Cache_Sets[tmp]=((b&0xffc00000)>>22)+1;
                cpuinfo->Cacheflushsize+=cpuinfo->U_Cache_Size[tmp];                
       		//cpuinfo->Total_D_Cache_Size+=(cpuinfo->num_cores/cpuinfo->Cache_shared[tmp])*cpuinfo->U_Cache_Size[tmp];
       		cpuinfo->Total_D_Cache_Size=(cpuinfo->num_cores/cpuinfo->Cache_shared[tmp])*cpuinfo->U_Cache_Size[tmp];//inclusive
		//cpuinfo->D_Cache_Size_per_Core+=cpuinfo->U_Cache_Size[tmp];
		cpuinfo->D_Cache_Size_per_Core=cpuinfo->U_Cache_Size[tmp];//inclusive
             }
         }
         i++;
       }
       while (a&0x1f);

    }
     a=0x80000000;   
     __asm__ __volatile__(
                "cpuid;"
              : "=a" (a), "=b" (b), "=c" (c), "=d" (d)
              : "a" (a)
        );
     if (a&0x80000000) max_ext=a; else max_ext=0;
     if(max_ext>=0x80000001)
     {
      a=0x80000001;
      __asm__ __volatile__(
                "cpuid;"
              : "=a" (a), "=b" (b), "=c" (c), "=d" (d)
              : "a" (a)
       );
       if (d&(1<<29)) cpuinfo->features|=X86_64;
       if (d&(1<<20)) cpuinfo->features|=NX;
     }
     //read the processor name string if available   
     if(max_ext>=0x80000004)
     {
      a=0x80000002;   
      __asm__ __volatile__(
                "cpuid;"
              : "=a" (a), "=b" (b), "=c" (c), "=d" (d)
              : "a" (a)
       );
      *((unsigned int*)&(cpuinfo->model_str[0]))=a;
      *((unsigned int*)&(cpuinfo->model_str[4]))=b;
      *((unsigned int*)&(cpuinfo->model_str[8]))=c;
      *((unsigned int*)&(cpuinfo->model_str[12]))=d;
      a=0x80000003;   
      __asm__ __volatile__(
                "cpuid;"
              : "=a" (a), "=b" (b), "=c" (c), "=d" (d)
              : "a" (a)
       );
      *((unsigned int*)&(cpuinfo->model_str[16]))=a;
      *((unsigned int*)&(cpuinfo->model_str[20]))=b;
      *((unsigned int*)&(cpuinfo->model_str[24]))=c;
      *((unsigned int*)&(cpuinfo->model_str[28]))=d;
      a=0x80000004;   
      __asm__ __volatile__(
                "cpuid;"
              : "=a" (a), "=b" (b), "=c" (c), "=d" (d)
              : "a" (a)
       );
      *((unsigned int*)&(cpuinfo->model_str[32]))=a;
      *((unsigned int*)&(cpuinfo->model_str[36]))=b;
      *((unsigned int*)&(cpuinfo->model_str[40]))=c;
      *((unsigned int*)&(cpuinfo->model_str[44]))=d;
     }
     else strcpy(cpuinfo->model_str,"unknown\0");

     if(max_ext>=0x80000008)
     {
      a=0x80000008;
      __asm__ __volatile__(
                "cpuid;"
              : "=a" (a), "=b" (b), "=c" (c), "=d" (d)
              : "a" (a)
       );
       cpuinfo->phys_addr_length=a&0x000000ff;
       cpuinfo->virt_addr_length=(a>>8)&0x000000ff;
     }
  }
  if(cpuinfo->features&TSC)
  {
     cpuinfo->rdtsc_latency=get_rdtsc_latency_x86_64(cpuinfo);
     get_clockrates_x86(cpuinfo);
  }

  #endif

  if (print)
  {
    printf("    architecture:   %s\n",cpuinfo->architecture);  
    printf("    vendor:         %s\n",cpuinfo->vendor);  
    printf("    processor-name: %s\n",cpuinfo->model_str);

    printf("    model:          Family %i, Model %i, Stepping %i\n",cpuinfo->family,cpuinfo->model,cpuinfo->stepping);

    printf("    frequency:      %llu MHz\n",cpuinfo->clockrate/1000000);

    if(cpuinfo->num_cores) printf("    total number of (logical) cores in system: %i\n",cpuinfo->num_cores);
    if(cpuinfo->num_cores_per_package) printf("    number of (logical) cores per package: %i\n",cpuinfo->num_cores_per_package);

    printf("    supported features:");
    if(cpuinfo->features&X86_64) printf(" X86_64");
    if(cpuinfo->features&FPU) printf(" FPU");
    if(cpuinfo->features&MMX) printf(" MMX");
    if(cpuinfo->features&MMX_EXT) printf(" MMX_EXT");
    if(cpuinfo->features&_3DNOW) printf(" 3DNOW");
    if(cpuinfo->features&_3DNOW_EXT) printf(" 3DNOW_EXT");
    if(cpuinfo->features&SSE) printf(" SSE");
    if(cpuinfo->features&SSE2) printf(" SSE2");
    if(cpuinfo->features&SSE3) printf(" SSE3");
    if(cpuinfo->features&SSSE3) printf(" SSSE3");
    if(cpuinfo->features&SSE4_1) printf(" SSE4.1");
    if(cpuinfo->features&SSE4_2) printf(" SSE4.2");
    if(cpuinfo->features&SSE4A) printf(" SSE4A");
    if(cpuinfo->features&SSE5) printf(" SSE5");
    if(cpuinfo->features&POPCNT) printf(" POPCNT");
    if(cpuinfo->features&CX8) printf(" CX8");
    if(cpuinfo->features&CX16) printf(" CX16");
    if(cpuinfo->features&FREQ_SCALING) printf(" FREQ_SCALING");
    if(cpuinfo->features&MONITOR) printf(" MONITOR");
    if(cpuinfo->features&NX) printf(" NX");
    if(cpuinfo->features&MTRR) printf(" MTRR");
    if(cpuinfo->features&TSC)   printf("\n                        TSC: %i cycles latency",cpuinfo->rdtsc_latency);
    if(cpuinfo->features&CLFLUSH) printf("\n                        CLFLUSH: %i Byte clflush-linesize\n",cpuinfo->clflush_linesize);

    if(cpuinfo->Cachelevels)
    {
     for(i=0;i<cpuinfo->Cachelevels;i++)
     {
        printf("    Level%i Cache:\n",i+1);
        if (cpuinfo->Cache_unified[i]) printf("      - unified Cache\n"); else printf("      - separated Instruction and Data Caches\n");
        if (cpuinfo->Cache_unified[i])
        {
          if (cpuinfo->U_Cache_Sets[i]==0) printf("      - %i Bytes, fully associative\n",cpuinfo->U_Cache_Size[i]);
          else if (cpuinfo->U_Cache_Sets[i]==1) printf("      - %i Bytes, direct mapped\n",cpuinfo->U_Cache_Size[i]);
          else printf("      - %i Bytes, %i-way set-associative\n",cpuinfo->U_Cache_Size[i],cpuinfo->U_Cache_Sets[i]);
        }
        else
        {
          if (cpuinfo->I_Cache_Sets[i]==0) printf("      - %i Bytes I-Cache, fully associative\n",cpuinfo->I_Cache_Size[i]);
          else if (cpuinfo->I_Cache_Sets[i]==1) printf("      - %i Bytes I-Cache, direct mapped\n",cpuinfo->I_Cache_Size[i]);
          else printf("      - %i Bytes I-Cache, %i-way set-associative\n",cpuinfo->I_Cache_Size[i],cpuinfo->I_Cache_Sets[i]);
          if (cpuinfo->D_Cache_Sets[i]==0) printf("      - %i Bytes D-Cache, fully associative\n",cpuinfo->D_Cache_Size[i]);
          else if (cpuinfo->D_Cache_Sets[i]==1)printf("      - %i Bytes D-Cache, direct mapped\n",cpuinfo->D_Cache_Size[i]);
          else printf("      - %i Bytes D-Cache, %i-way set-associative\n",cpuinfo->D_Cache_Size[i],cpuinfo->D_Cache_Sets[i]);
        }
        if ((cpuinfo->Cache_shared[i])>1) printf("      - shared between %i CPU(s)\n",cpuinfo->Cache_shared[i]);
        else printf("      - per CPU\n");
        printf("      - %i Byte Cachelines\n",cpuinfo->Cacheline_size[i]);
     }
    }

    if (cpuinfo->num_pagesizes)
    {
      printf("    supported pagesizes:");
      for (i=0;i<cpuinfo->num_pagesizes;i++)
      {
        if(i) printf(",");
        if(cpuinfo->pagesizes[i]>=(1024*1048576)) printf(" %llu GiByte",cpuinfo->pagesizes[i]/(1024*1048576));
        else if(cpuinfo->pagesizes[i]>=1048576) printf(" %llu MiByte",cpuinfo->pagesizes[i]/1048576);
        else if(cpuinfo->pagesizes[i]>=1024) printf(" %llu KiByte",cpuinfo->pagesizes[i]/1024);
      }
      printf("\n");
    }
    if (cpuinfo->virt_addr_length) printf("    virtual address length:  %u bits\n",cpuinfo->virt_addr_length);
    if (cpuinfo->phys_addr_length) printf("    physical address length: %u bits\n",cpuinfo->phys_addr_length);

    if ((cpuinfo->tlblevels)&&(cpuinfo->num_pagesizes))
    {
      int tmp;
      char tmpstring[256];
      for(i=0;i<=cpuinfo->tlblevels;i++)
      {
        tmp=0;
        for(j=0;j<cpuinfo->num_pagesizes;j++)
        {
           if (cpuinfo->I_TLB_Size[i][j]!=0) tmp=1;
        }
        if (tmp)
        {
          printf("    Level%i ITLB:\n",i+1);
          for(j=0;j<cpuinfo->num_pagesizes;j++)
          {
            if(cpuinfo->pagesizes[j]>=(1024*1048576)) sprintf(tmpstring,"%llu GiByte pages\0",cpuinfo->pagesizes[j]/(1024*1048576));
            else if(cpuinfo->pagesizes[j]>=1048576) sprintf(tmpstring,"%llu MiByte pages\0",cpuinfo->pagesizes[j]/1048576);
            else if(cpuinfo->pagesizes[j]>=1024) sprintf(tmpstring,"%llu KiByte pages\0",cpuinfo->pagesizes[j]/1024);

            if (cpuinfo->I_TLB_Size[i][j]!=0)
            {

              if (cpuinfo->I_TLB_Sets[i][j]>1) printf("      %i entries for %s, %i-way set associative\n",cpuinfo->I_TLB_Size[i][j],tmpstring,cpuinfo->I_TLB_Sets[i][j]);
              else if (cpuinfo->I_TLB_Sets[i][j]==1) printf("      %i entries for %s, direct mapped\n",cpuinfo->I_TLB_Size[i][j],tmpstring);
              else printf("      %i entries for %s, fully associative\n",cpuinfo->I_TLB_Size[i][j],tmpstring);
            }
          }
        }
        tmp=0;
        for(j=0;j<cpuinfo->num_pagesizes;j++)
        {
           if (cpuinfo->D_TLB_Size[i][j]!=0) tmp=1;
        }
        if (tmp)
        {
          printf("    Level%i DTLB:\n",i+1);
          for(j=0;j<cpuinfo->num_pagesizes;j++)
          {
            if(cpuinfo->pagesizes[j]>=(1024*1048576)) sprintf(tmpstring,"%llu GiByte pages\0",cpuinfo->pagesizes[j]/(1024*1048576));
            else if(cpuinfo->pagesizes[j]>=1048576) sprintf(tmpstring,"%llu MiByte pages\0",cpuinfo->pagesizes[j]/1048576);
            else if(cpuinfo->pagesizes[j]>=1024) sprintf(tmpstring,"%llu KiByte pages\0",cpuinfo->pagesizes[j]/1024);

            if (cpuinfo->D_TLB_Size[i][j]!=0)
            {

              if (cpuinfo->D_TLB_Sets[i][j]>1) printf("      %i entries for %s, %i-way set associative\n",cpuinfo->D_TLB_Size[i][j],tmpstring,cpuinfo->D_TLB_Sets[i][j]);
              else if (cpuinfo->D_TLB_Sets[i][j]==1) printf("      %i entries for %s, direct mapped\n",cpuinfo->D_TLB_Size[i][j],tmpstring);
              else printf("      %i entries for %s, fully associative\n",cpuinfo->D_TLB_Size[i][j],tmpstring);
            }
          }
        }
        tmp=0;
        for(j=0;j<cpuinfo->num_pagesizes;j++)
        {
           if (cpuinfo->U_TLB_Size[i][j]!=0) tmp=1;
        }
        if (tmp)
        {
          printf("    Level%i TLB (code and data):\n",i+1);
          for(j=0;j<cpuinfo->num_pagesizes;j++)
          {
            if(cpuinfo->pagesizes[j]>=(1024*1048576)) sprintf(tmpstring,"%llu GiByte pages\0",cpuinfo->pagesizes[j]/(1024*1048576));
            else if(cpuinfo->pagesizes[j]>=1048576) sprintf(tmpstring,"%llu MiByte pages\0",cpuinfo->pagesizes[j]/1048576);
            else if(cpuinfo->pagesizes[j]>=1024) sprintf(tmpstring,"%llu KiByte pages\0",cpuinfo->pagesizes[j]/1024);

            if (cpuinfo->U_TLB_Size[i][j]!=0)
            {

              if (cpuinfo->U_TLB_Sets[i][j]>1) printf("      %i entries for %s, %i-way set associative\n",cpuinfo->U_TLB_Size[i][j],tmpstring,cpuinfo->U_TLB_Sets[i][j]);
              else if (cpuinfo->U_TLB_Sets[i][j]==1) printf("      %i entries for %s, direct mapped\n",cpuinfo->U_TLB_Size[i][j],tmpstring);
              else printf("      %i entries for %s, fully associative\n",cpuinfo->U_TLB_Size[i][j],tmpstring);
            }
          }
        }
      }
    }
    fflush(stdout);
  }
}

/**
 * flushes content of buffer from all cache-levels
 * @param buffer pointer to the buffer
 * @param size size of buffer in Bytes
 * @return 0 if successful
 *         -1 if not available
 */
int inline clflush(void* buffer,unsigned long long size,cpu_info_t cpuinfo)
{
  #if defined (__x86_64__)
  unsigned long long addr,passes,linesize;

  if(!(cpuinfo.features&CLFLUSH) || !cpuinfo.clflush_linesize) return -1;

  //printf("flushing cache using clflush\n");

  addr = (unsigned long long) buffer;
  linesize = (unsigned long long) cpuinfo.clflush_linesize;

   __asm__ __volatile__("mfence;"::);
   for(passes = (size/linesize);passes>0;passes--)
   {
      __asm__ __volatile__("clflush (%%rax);":: "a" (addr));
      addr+=linesize;
   }
   __asm__ __volatile__("mfence;"::);
  #endif

  return 0;
}

int inline write_nt(void* buffer,unsigned long long size,cpu_info_t cpuinfo)
{
  #if defined (__x86_64__)
  unsigned long long addr,passes,linesize;

  //printf("flushing cache using non-temporal stores\n");

  addr = (unsigned long long) buffer;
  linesize = 16;
  
  addr=addr&(0xffffffffffffff00);

   __asm__ __volatile__("mfence;"::);
   for(passes = (size/linesize)-1;passes>0;passes--)
   {
      __asm__ __volatile__("movdqa (%%rax),%%xmm0;movntdq %%xmm0, (%%rax);":: "a" (addr): "%xmm0");
      addr+=linesize;
   }
   __asm__ __volatile__("mfence;"::);
  #endif

  return 0;
}

/**
 * prefetches content of buffer 
 * @param buffer pointer to the buffer
 * @param size size of buffer in Bytes
 * @return 0 if successful
 *         -1 if not available
 */
int inline prefetch(void* buffer,unsigned long long size, cpu_info_t cpuinfo)
{
  #if defined (__x86_64__)
  unsigned long long addr,passes,linesize;
  int i;

  if(cpuinfo.features&SSE) return -1;

  addr = (unsigned long long) buffer;
  linesize = 256;
  for (i=cpuinfo.Cachelevels;i>0;i--)
  {
    if (cpuinfo.Cacheline_size[i-1]<linesize) linesize=cpuinfo.Cacheline_size[i-1];
  }

  for(passes = (size/linesize);passes>0;passes--)
  {
    __asm__ __volatile__("prefetcht0 (%%rax);":: "a" (addr));
    addr+=linesize;
  }
  #endif

  return 0;
}

/**
 * flushes data from the specified cachelevel
 * @param level the cachelevel that should be flushed
 * @param num_flushes number of accesses to each cacheline
 * @param mode FLUSH_RO: use memory read-only
 *             FLUSH_RW: use memory read-write 
 * @param buffer pointer to a memory area, size of the buffer has to be 
 *               has to be larger than 2 x sum of all cachelevels <= level
 * @return 0 if successful, -1 on error
 */
int inline cacheflush(int level,int num_flushes,int mode,void* buffer,cpu_info_t cpuinfo)
{
  unsigned long long stride=cpuinfo.Cacheline_size[level-1]/num_flushes;
  unsigned long long size=0;
  unsigned int i,j,tmp=0x0fa38b09;

  if (level>cpuinfo.Cachelevels) return -1;

  if (!strcmp(cpuinfo.vendor,"AuthenticAMD"))for (i=0;i<level;i++)
  {
     if (cpuinfo.Cache_unified[i]) size+=cpuinfo.U_Cache_Size[i];
     else size+=cpuinfo.D_Cache_Size[i];
  }
  if (!strcmp(cpuinfo.vendor,"GenuineIntel"))
  {
     i=level-1;
     if (cpuinfo.Cache_unified[i]) size=cpuinfo.U_Cache_Size[i];
     else size=cpuinfo.D_Cache_Size[i];
  } 

  size*=12;
  size/=10;

  if (stride<sizeof(unsigned int)) stride=sizeof(unsigned int);
  
  j=num_flushes;
  while(j--)
  {
    for (i=0;i<size;i+=stride)
    {
      //tmp|=*((int*)((unsigned long long)buffer+i));
      *((int*)((unsigned long long)buffer+i))=tmp;
    }
  }
  if (mode==MODE_EXCLUSIVE) 
  {
    clflush(buffer,size,cpuinfo);
    j=num_flushes;
    while(j--)
    {
     for (i=0;i<size;i+=stride)
     {
       tmp|=*((int*)((unsigned long long)buffer+i));
     }
     *((int*)((unsigned long long)buffer+i))=tmp;
    }
  }
  if (mode==MODE_INVALID) 
  {
    clflush(buffer,size,cpuinfo);
  }

  return 0;
}
